﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;
using System.Security.Cryptography;

namespace SecureCommander.Core.SecurityManager
{
     public class RSAAlgorithm
    {
        private RSACryptoServiceProvider RSAProvider;
        private string _strPublickey;

        public string StrPublickey
        {
            get { return _strPublickey; }
            set { _strPublickey = value; }
        }


        private string _strPrivatekey;

        public string StrPrivatekey
        {
            get { return _strPrivatekey; }
            set { _strPrivatekey = value; }
        }


        public RSAAlgorithm(int keysize)
        {                     
            RSAProvider = new RSACryptoServiceProvider(keysize);
            StrPrivatekey = RSAProvider.ToXmlString(true);
            StrPublickey = RSAProvider.ToXmlString(false);
        }

        public RSAAlgorithm()
        {
            int keysize = 512;
            //CspParameters cspParam = new CspParameters(1);
            //cspParam.KeyContainerName = "DSAKeyContainer";
            //cspParam.ProviderName = "Microsoft Strong Cryptographic Provider";
            //cspParam.Flags = CspProviderFlags.UseMachineKeyStore;
            RSAProvider = new RSACryptoServiceProvider(keysize);
            StrPrivatekey = RSAProvider.ToXmlString(true);
            StrPublickey = RSAProvider.ToXmlString(false);
        }

        public RSAAlgorithm(String key)
        {
            // = new RSACryptoServiceProvider();
            //CspParameters cspParam = new CspParameters(1);
            //cspParam.KeyContainerName = "DSAKeyContainer";
            //cspParam.ProviderName = "Microsoft Strong Cryptographic Provider";
            //cspParam.Flags = CspProviderFlags.UseMachineKeyStore;
            RSAProvider = new RSACryptoServiceProvider();
            RSAProvider.FromXmlString(key);   
            
        }


        public int getKeySize()
        {
            return RSAProvider.KeySize;
        }

        //public byte[] Encrypt(byte[] input,bool pad)
        //{
        //    int keySize = RSAProvider.KeySize / 8;
        //    int maxLength = keySize - 42;
        //    int dataLength = input.Length;
        //    int iterations = dataLength / maxLength;
        //    StringBuilder stringBuilder = new StringBuilder();
        //    byte[] encryptedBytes = null;
        //    ArrayList arrEncryptedBytes = new ArrayList();
        //    for (int i = 0; i <= iterations; i++)
        //    {
        //        byte[] tempBytes = new byte[(dataLength - maxLength * i > maxLength) ? maxLength : dataLength - maxLength * i];
        //        Buffer.BlockCopy(input, maxLength * i, tempBytes, 0, tempBytes.Length);
        //        encryptedBytes = RSAProvider.Encrypt(tempBytes, pad);
        //        Array.Reverse(encryptedBytes);
        //        arrEncryptedBytes.Add(encryptedBytes);

        //    }

        //    MemoryStream ms = new MemoryStream();
        //    try
        //    {
        //        for (int i = 0; i < arrEncryptedBytes.Count; i++)
        //        {
        //            byte[] tmp = (byte[])arrEncryptedBytes[i];
        //            ms.Write(tmp, 0, tmp.Length);
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        throw;
        //    }
            
        //    return ms.ToArray();
            
        //}

        //public byte[] Decryption(byte[] input,bool pad)
        //{
            
        //    RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider(keysize);
        //    string PriKey = File.ReadAllText(txtprikeyDe.Text);
        //    rsa2.FromXmlString(PriKey);

        //    //int base64BlockSize1 = ((rsa2.KeySize / 8) % 3 != 0) ? (((rsa2.KeySize / 8) / 3) * 4) + 4 : ((rsa2.KeySize / 8) / 3) * 4;
        //    int base64BlockSize = (rsa2.KeySize / 8);
        //    int iterations = bytes.Length / base64BlockSize;

        //    ArrayList arrDecryptedBytes = new ArrayList();
        //    for (int i = 0; i < iterations; i++)
        //    {
        //        byte[] encryptedBytes = new byte[base64BlockSize];
        //        Buffer.BlockCopy(bytes, base64BlockSize * i, encryptedBytes, 0, base64BlockSize);

        //        Array.Reverse(encryptedBytes);
        //        arrDecryptedBytes.Add(rsa2.Decrypt(encryptedBytes, false));
        //    }
        //    FileStream fileOut = File.Open(txtoutDe.Text, FileMode.OpenOrCreate);
        //    BinaryWriter write = new BinaryWriter(fileOut);
        //    try
        //    {
        //        for (int i = 0; i < arrDecryptedBytes.Count; i++)
        //        {
        //            write.Write((byte[])arrDecryptedBytes[i]);
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        MessageBox.Show("write to file error!");
        //    }
        //    finally
        //    {
        //        write.Close();
        //    }

        //}


        public Byte[] Merge2Bytes(Byte[] a1, Byte[] a2)
        {
            Byte[] rv = new Byte[a1.Length + a2.Length];
            System.Buffer.BlockCopy(a1, 0, rv, 0, a1.Length);
            System.Buffer.BlockCopy(a2, 0, rv, a1.Length, a2.Length);
            return rv;
        }

        public Byte[] SubBytes(Byte[] bytes, int idx, int length)
        {
            Byte[] rv = new Byte[length];
            for (int i = 0; i < length; i++)
                rv[i] = bytes[idx + i];
            return rv;
        }

        public Byte[] Encrypt(Byte[] bytes, bool pad)
        {
            int dwKeySize = RSAProvider.KeySize;
            Int32 keySize = dwKeySize / 8;
            //Byte[] bytes = Encoding.UTF32.GetBytes(inputString);
            Int32 maxLength = keySize - 42;
            Int32 dataLength = bytes.Length;
            Int32 iterations = dataLength / maxLength;
            Byte[] bResult = new Byte[0];
            for (Int32 i = 0; i <= iterations; i++)
            {
                Byte[] tempBytes = new Byte[
                        (dataLength - maxLength * i > maxLength) ? maxLength :
                                                      dataLength - maxLength * i];
                Buffer.BlockCopy(bytes, maxLength * i, tempBytes, 0,
                                  tempBytes.Length);
                Byte[] encryptedBytes = RSAProvider.Encrypt(tempBytes, pad);
                Array.Reverse(encryptedBytes);
                bResult = Merge2Bytes(bResult, encryptedBytes);
                //stringBuilder.Append(Convert.ToBase64String(encryptedBytes));
            }
            return bResult;
        }
        public Byte[] Decrypt(Byte[] bytes, bool pad)
        {            
            int dwKeySize = RSAProvider.KeySize;
            Int32 base64BlockSize = ((dwKeySize / 8) % 3 != 0) ?
              (((dwKeySize / 8) / 3) * 4) + 4 : ((dwKeySize / 8) / 3) * 4;
            Int32 pow = 1;
            while (Math.Pow(2, pow) < base64BlockSize)
                pow++;
            base64BlockSize = (Int32)Math.Pow(2, pow - 1);
            Int32 iterations = bytes.Length / base64BlockSize;
            ArrayList arrayList = new ArrayList();
            for (Int32 i = 0; i < iterations; i++)
            {
                byte[] encryptedBytes = SubBytes(bytes, base64BlockSize * i, base64BlockSize);
                Array.Reverse(encryptedBytes);
                arrayList.AddRange(RSAProvider.Decrypt(encryptedBytes, pad));
            }
            
            return arrayList.ToArray(Type.GetType("System.Byte")) as byte[];
        }


        ////Decrypt...
        //public string DecryptString(string inputString)
        //{
        //    int base64BlockSize = ((m_dwKeySize / 8) % 3 != 0) ? (((m_dwKeySize / 8) / 3) * 4) + 4 : ((m_dwKeySize / 8) / 3) * 4;
        //    int iterations = inputString.Length / base64BlockSize;
        //    ArrayList arrayList = new ArrayList();
        //    for (int i = 0; i < iterations; i++)
        //    {
        //        byte[] encryptedBytes = Convert.FromBase64String(inputString.Substring(base64BlockSize * i, base64BlockSize));
        //        // Be aware the RSACryptoServiceProvider reverses the order of encrypted bytes after encryption and before decryption.
        //        // If you do not require compatibility with Microsoft Cryptographic API (CAPI) and/or other vendors.
        //        // Comment out the next line and the corresponding one in the EncryptString function.
        //        Array.Reverse(encryptedBytes);
        //        arrayList.AddRange(this.m_myRSA.Decrypt(encryptedBytes, true));
        //    }
        //    return Encoding.UTF32.GetString(arrayList.ToArray(Type.GetType("System.Byte")) as byte[]);
        //}


        //public static byte[] TrimEnd(byte[] inBuffer, byte match)
        //{
        //    byte[] result = null;
        //    for (int i = inBuffer.Length - 1; i >= 0; --i)
        //    {
        //        if (inBuffer[i] != match)
        //        {
        //            result = new byte[i + 1];
        //            Array.Copy(inBuffer, result, result.Length);
        //            break;
        //        }
        //    }
        //    return result;
        //}

        //public byte[] Encrypt(byte[] inBuffer, bool pad)
        //{
        //    byte[] buffer = null;
        //    MemoryStream msInput = null;
        //    MemoryStream msOutput = null;

        //    try
        //    {
        //        msInput = new MemoryStream(inBuffer);
        //        // Cấp buffer để đủ chứa kết quả trả về
        //        buffer = new byte[RSAProvider.KeySize / 8];
        //        msOutput = new MemoryStream(buffer);
        //        Encrypt(msInput, msOutput, pad);
        //    }
        //    catch (System.Exception)
        //    {
        //        throw;
        //    }
        //    finally
        //    {
        //        if (msOutput != null)
        //            msOutput.Close();
        //        if (msInput != null)
        //            msInput.Close();
        //    }

        //    return buffer;
        //}
        //public byte[] Decrypt(byte[] inBuffer, bool pad)
        //{
        //    byte[] result = null;
        //    MemoryStream msInput = null;
        //    MemoryStream msOutput = null;
        //    try
        //    {
        //        msInput = new MemoryStream(inBuffer);
        //        // Cấp buffer để đủ chứa kết quả trả về
        //        byte[] temp = new byte[RSAProvider.KeySize / 8];
        //        msOutput = new MemoryStream(temp);
        //        Decrypt(msInput, msOutput, pad);
        //        result = TrimEnd(temp, 0);
        //    }
        //    catch (System.Exception)
        //    {
        //        throw;
        //    }
        //    finally
        //    {
        //        if (msOutput != null)
        //            msOutput.Close();
        //        if (msInput != null)
        //            msInput.Close();
        //    }

        //    return result;
        //}
        //public void Encrypt(Stream inStream, Stream outStream, bool pad)
        //{
        //    try
        //    {
        //        int max = (RSAProvider.KeySize / 8) - 11;

        //        byte[] PlainText = new byte[max];
        //        byte[] EncryptData;

        //        int count = 0;
        //        while ((count = inStream.Read(PlainText, 0, max)) != 0)
        //        {
        //            byte[] temp = null;
        //            if (count == max)
        //                temp = PlainText;
        //            else
        //            {
        //                temp = new byte[count];
        //                Array.Copy(PlainText, temp, count);
        //            }
        //            EncryptData = RSAProvider.Encrypt(temp, pad);
        //            outStream.Write(EncryptData, 0, EncryptData.Length);
        //        }
        //    }
        //    catch (System.Exception)
        //    {
        //        throw;
        //    }
        //}
        //public void Decrypt(Stream inStream, Stream outStream, bool pad)
        //{
        //    try
        //    {
        //        int max = RSAProvider.KeySize / 8;

        //        byte[] EncryptData = new byte[max];
        //        byte[] PlainText;
        //        int count;

        //        while ((count = inStream.Read(EncryptData, 0, max)) != 0)
        //        {
        //            PlainText = RSAProvider.Decrypt(EncryptData, pad);
        //            outStream.Write(PlainText, 0, PlainText.Length);
        //        }
        //    }
        //    catch (System.Exception)
        //    {
        //        throw;
        //    }
        //}
    }
}
